#ifndef NetMgr_H_
#define NetMgr_H_
#include <stdint.h>
#include <functional>
#include <thread>
#include <map>
#include <unordered_map>
#include <list>
#include <mutex>
#include <chrono>
#include <condition_variable>
#include <vector>
#include <AfSocket.h>




class Pipe
{
public:
	Pipe();
	virtual ~Pipe();
	int  Create();
	int   Write(void* buf, int len);
	int   Read(void* buf, int len);
	void  Close();

	socket_t Read() const { return pipe_fd_[0]; }
	socket_t Write() const { return pipe_fd_[1]; }

private:
	socket_t pipe_fd_[2];
};


enum EventType
{
	EVENT_NONE = 0,
	EVENT_IN = 1,
	EVENT_PRI = 2,
	EVENT_OUT = 4,
	EVENT_ERR = 8,
	EVENT_HUP = 16,
	EVENT_RDHUP = 8192
};

class Channel
{
public:
	typedef std::function<void()> EventCallback;

	Channel() = delete;

	Channel(socket_t sockfd)
		: sockfd_(sockfd)
	{

	}

	virtual ~Channel() {};

	void SetReadCallback(const EventCallback& cb)
	{
		read_callback_ = cb;
	}

	void SetWriteCallback(const EventCallback& cb)
	{
		write_callback_ = cb;
	}

	void SetCloseCallback(const EventCallback& cb)
	{
		close_callback_ = cb;
	}

	void SetErrorCallback(const EventCallback& cb)
	{
		error_callback_ = cb;
	}

	socket_t GetSocket() const { return sockfd_; }

	int  GetEvents() const { return events_; }
	void SetEvents(int events) { events_ = events; }

	void EnableReading()
	{
		events_ |= EVENT_IN;
	}

	void EnableWriting()
	{
		events_ |= EVENT_OUT;
	}

	void DisableReading()
	{
		events_ &= ~EVENT_IN;
	}

	void DisableWriting()
	{
		events_ &= ~EVENT_OUT;
	}

	bool IsNoneEvent() const { return events_ == EVENT_NONE; }
	bool IsWriting() const { return (events_ & EVENT_OUT) != 0; }
	bool IsReading() const { return (events_ & EVENT_IN) != 0; }

	void HandleEvent(int events)
	{
		if (events & (EVENT_PRI | EVENT_IN)) {
			read_callback_();
		}

		if (events & EVENT_OUT) {
			write_callback_();
		}

		if (events & EVENT_HUP) {
			close_callback_();
			return;
		}

		if (events & (EVENT_ERR)) {
			error_callback_();
		}
	}

private:
	EventCallback read_callback_ = [] {};
	EventCallback write_callback_ = [] {};
	EventCallback close_callback_ = [] {};
	EventCallback error_callback_ = [] {};

	socket_t sockfd_ = 0;
	int events_ = 0;
};

typedef std::shared_ptr<Channel> ChannelPtr;

using Task = std::function<void()>; 

class TimerNet
{
public:
	TimerNet(int64_t delay, std::function<bool()> cb) : m_iDelay(delay), m_cb(cb) {};
	~TimerNet() {};
	int64_t m_iDelay = 0;
	std::function<bool()> m_cb;
	int64_t m_iTimerId = -1;
};

class WorkerThreadN
{
public:
	WorkerThreadN();

	int32_t StartRun(std::string threadName);
	void StopRun();
	~WorkerThreadN();

	int32_t UpdateChannel(ChannelPtr channel);
	int32_t RemoveChannel(ChannelPtr& channel);

	void PostTask(Task task);

	void InvokTask(Task task);


	virtual int64_t AddTimer(int64_t iDelayMs, std::function<bool()> fcb);

	virtual int32_t DelTimer(int64_t timerId);

	std::string GetThreadId();

	int64_t getCurrentTicket();
public:



private:
	void RunLoop();
	
	void SetThreadName(std::string threadName);

private:

	int64_t flushDelayTask(uint64_t now_time);
	int64_t getMinDelay();

private:
	std::mutex _mutex;
	std::condition_variable _condition;
	bool m_bStart = false;
	int64_t m_iTimerId = 0;

	std::list<Task> _queue;

	std::thread* m_loopThread = NULL;
	bool m_bExitThread = false;
	std::thread::id _loopThreadId;
	
	Pipe m_oPipe;

	std::mutex mutex_;
	std::unordered_map<socket_t, ChannelPtr> channels_;

	std::multimap<uint64_t, std::shared_ptr<TimerNet> > m_delayTask;

};


class EventLoopN
{
public:
	EventLoopN(const EventLoopN&) = delete;
	EventLoopN& operator = (const EventLoopN&) = delete;
	EventLoopN();  //std::thread::hardware_concurrency()
	virtual ~EventLoopN();


	int32_t Loop(std::string name_thread, uint32_t num_threads = 1);
	void Quit();

	std::shared_ptr<WorkerThreadN> GetTaskScheduler();

	virtual void UpdateChannel(ChannelPtr channel);
	virtual void RemoveChannel(ChannelPtr& channel);


private:
	std::mutex mutex_;
	uint32_t num_threads_ = 1;
	std::string m_name = "";
	uint32_t index_ = 1;
	std::vector<std::shared_ptr<WorkerThreadN>> task_schedulers_;

};


class NetMgr
{
protected:
	NetMgr();

public:
	static NetMgr* GetInstance();

	int32_t Init(uint32_t num_threads = 1, std::string name_thread ="Net");

	virtual ~NetMgr();

public:

	EventLoopN m_oEventLoop;

private:
	static NetMgr *m_oInstance;
	static std::once_flag m_flag;
};


#endif